Microsoft Azure IoT Hub應(yīng)用 – 第二部分:連接傳感器以及 IoT 車輛
1). 簡介
這是關(guān)于 IoT 應(yīng)用開發(fā)系列文章中的第二篇。本文繼續(xù)關(guān)注傳感器讀取以及向云端發(fā)送收集到的數(shù)據(jù)。Toradex Colibri VF61 模塊 + Iris 底板繼續(xù)作為本次演示的嵌入式系統(tǒng)。圖 1 展示了本系列文章所介紹應(yīng)用整體框圖。
圖1:應(yīng)用框圖
2). 添加傳感器模塊到Iris 底板
項目中使用的傳感器產(chǎn)生數(shù)據(jù),模塊通過 Wi-Fi 聯(lián)網(wǎng):
./ MPU-6050 陀螺儀 + 加速度和溫度
./ HC-SR04 超聲波模塊
./ IKeyes GPS shield v1.2
./ WL250N USB Wi-Fi
MPU-6050 已經(jīng)提供了內(nèi)核驅(qū)動模塊,能夠同 Linux應(yīng)用通信(適用于 Toradex Vybrid 的4.4.0Linux 內(nèi)核版本 )。 該文檔 說明了使用模塊硬件接口的 device tree 配置。該模塊驅(qū)動不能直接添加到內(nèi)核中,需要編譯的時候包含進(jìn)來。這篇文章 詳細(xì)說明了如何配置、編譯和更新內(nèi)核。如果 MPU-6050 的 I²C 地址和板載 RTC(0x68)沖突,最簡單的解決方法是將 MPU-6050 的 AD0 接至高電平,這可以將其地址變?yōu)?0x69。
HC-SR04 在 Github 上有 驅(qū)動模塊 ,其中的一個分支可以針對Colibri VF61 的 4.4.0 內(nèi)核進(jìn)行編譯。針對 Toradex 模塊的源碼以及編譯好的驅(qū)動模塊可以從這里下載。
GPS 模塊通過 UART 通信,其與 GPSD 服務(wù)連接。更多關(guān)于GPSD 的信息請查看這里.。如果你想要 編譯自己的鏡像,GPSD 也提供了 OpenEmbeddedrecipe。
依次配置 GPSD、加載 HC-SR04 驅(qū)動以及向云端發(fā)送數(shù)據(jù)。無論是重啟還是開機,init 服務(wù)都會被調(diào)用。如果本文使用的 Githubrepository 已經(jīng)復(fù)制到目標(biāo)板上,你會發(fā)現(xiàn)服務(wù)文件(car.service)和 init 腳本(init.sh)在主文件夾中。為了使其工作,還需要其他一些步驟。首先,Github repository 需要復(fù)制到 /home/root 目錄,這是默認(rèn)的路徑。然后 car.service 需要放在 /lib/systemd/system 中,啟用相應(yīng)的服務(wù)。下面的步驟描述了操作步驟:
---------------------------
root@colibri-vf:~# git clonehttps://github.com/leograba/azure-iot-car.git
root@colibri-vf:~# cd azure-iot-car
root@colibri-vf:~# cp car.service/lib/systemd/system
root@colibri-vf:~# systemctl enablecar.service
---------------------------
如果想要在啟動時停止該服務(wù),例如停止向 IoT Hub 發(fā)送數(shù)據(jù),那么可以通過下面命令停止:
---------------------------
root@colibri-vf:~# systemctl stopcar.service
---------------------------
USB Wi-Fi 模塊 WL250N 可以直接使用,但是仍舊需要配置才能連接網(wǎng)絡(luò)。如何配置連接的說明可以參考這里。
關(guān)于模塊和 Iris 底板之間的連接,只能使用 X16 排針引腳。Iris 技術(shù)手冊 提供了關(guān)于接口、連接器等的信息,如果需要可以參閱 Colibri VF61 CoM 技術(shù)手冊。表 1 描述了 Iris 和模塊之間的引腳連接。圖 2 是 MPU-6050 和 HC-SR04 在早期研發(fā)階段的連接。
---------------------------
表 1:傳感器和 Iris 底板連接
Iris pin header (x16) Irispin description Module Pin
5 I²C SDA MPU 6050 SDA
6 I²C SCL MPU 6050 SCL
7 GND MPU 6050 / HC-SR04 / GPS GND/ GND / GND
12 +5V MPU 6050 / HC-SR04 / GPS VCC / VCC / 5V
17 GPIO HC-SR04 Trig
18 GPIO HC-SR04 Echo
31 UART_B Rx GPS Tx
32 UART_B Tx GPS Rx
33 +3.3V HC-SR04 AD0
圖 2:MPU-6050 以及 HC-SR04 和 Iris 連接
3). IoT 車輛
在所有的模塊連接到 Toradex 嵌入式系統(tǒng)后,接下來就需要把它嵌入到遙控車?yán)?,如圖 3 所示。這是簡單的步驟,但仍舊需要在一些地方引起注意。
圖 3:IoT 原型
因為 GPS 模塊有主動天線,模塊放置在 Toradex 系統(tǒng)下,天線接到車頂外面。為了安裝超聲波測距模塊,如圖 3 所示在保險桿位置開了兩個孔。加速器傳感器則被固定在電路板上,PCB 板與地面平行,這可以直接使用模塊的數(shù)據(jù)而不需要修正(在實際應(yīng)用中這往往是需要的)。
嵌入式系統(tǒng)的電源選用兩芯(2S – 7.4V)1200mAh 可充電鋰電池??紤]到目前系統(tǒng)耗電為 200mA,鋰電池實際放電 不應(yīng)該超過容量的 80% 的規(guī)律,系統(tǒng)能夠工作4.8 個小時。圖 4 為最終的原型。
圖 4:IoT 車輛最終原型
4). 讀取傳感器并向云端發(fā)送數(shù)據(jù)
MPU-6050 和 HC-SR04 可以通過訪問文件系統(tǒng)讀取數(shù)據(jù),讀取 GPS 數(shù)據(jù)需要使用 Bancroft 同 GPSD 通信,獲取解析的數(shù)據(jù)。
從 HC-SR04 由內(nèi)核模塊返回的值為發(fā)送一個脈沖至其返回的時間,單位毫秒。該值需要乘以聲音的速度并除以 2E6,因為一半的時間用于超聲波的發(fā)送,另一半是反射:
distance = (value*sound_speed)/2000000
MPU-6050 的數(shù)據(jù)具有一個比例,一旦獲取精度配置。同樣,每一個溫度傳感器都已不同的偏移。在本文中,MPU-6050 會采用默認(rèn)的配置,一般的方法就可以換算讀取的數(shù)據(jù):
value = (raw_value+offset)*scale
換算后各個值的單位:加速度 - m/s²; 陀螺儀 - ?/s ;溫度 - ?C.
GPS 模塊返回如下的數(shù)據(jù):
---------------------------
{
timestamp: 1311296682000,
latitude: 45.456445,
longitude: -73.569651667,
altitude: 28.9,
speed: 11,
track: 10.3788,
geometries: { type: 'Point', coordinates: [ -73.569651667, 45.456445,28.9 ] }
}
---------------------------
讀取和向 IoT Hub 發(fā)送數(shù)據(jù)的應(yīng)用是由第一部分博文中修改該而來的 send_data.js。對應(yīng)目前應(yīng)用的文件是 send_data_from_sensors.js,這個可以在先前復(fù)制到目標(biāo)板上的Github repository 中找到。修改后的主要需要注意的是無論什么時候讀取到新的數(shù)據(jù),Bancroft 模塊都會觸發(fā)事件。對于訪問傳感器的路徑, MPU-6050 是 /sys/bus/iio/devices/iio:device2/,HC-SR04 是/sys/class/hcsr04/。下面是部分代碼的說明。
首先,MPU-6050 的偏移和比例變量可以同步讀取,防止代碼在偏移和比例變量確定之前讀取數(shù)值并計算。同樣,保存需要發(fā)送到云端的數(shù)據(jù)的變量也需要申明:
---------------------------
//Read some offset and scale constants fromthe MPU-6050 and convert to number
var temp_offset =+fs.readFileSync('/sys/bus/iio/devices/iio:device2/in_temp_offset');
var temp_scale =+fs.readFileSync('/sys/bus/iio/devices/iio:device2/in_temp_scale');
var accel_scale =+fs.readFileSync('/sys/bus/iio/devices/iio:device2/in_accel_scale');
var anglvel_scale =+fs.readFileSync('/sys/bus/iio/devices/iio:device2/in_anglvel_scale');
var gps_coordinates ;//variable to hold thegps coordinates
// Data to be sent to the cloud
var timenow, temperature, Distance,Acceleration = {}, Gyroscope = {};
---------------------------
然后處理對應(yīng)用至關(guān)重要的 GPS 數(shù)據(jù)。無論什么時候坐標(biāo)被更新,其都會保存在變量中,一旦與模塊之間連接丟失,它都會嘗試重新連接:
---------------------------
// gps events
bancroft.on('location', function (location){//updates the gps coordinates variable
location.geometries = "point";
gps_coordinates = location;
console.log('got new location',gps_coordinates);
});
bancroft.on('disconnect', function (err){//if gps is disconnected
bancroft = new Bancroft();//tries toreconnect once
console.log('trying to reconnect gps...');
});
最后一部分代碼是循環(huán)調(diào)用函數(shù)讀取傳感器并將數(shù)據(jù)發(fā)送至 IoT Hub。每一個函數(shù)采用獨立的循環(huán),使得代碼更加靈活,例如,讀取傳感器數(shù)據(jù)并保存到備份文件需要比發(fā)送到云端更加頻繁:
---------------------------
// Loops that call the functions to readsensors and send to the cloud
sendInterval.handlerGet =setInterval(getAllSensors, sendInterval.timerGet);
sendInterval.handlerSend =setInterval(sendToIotHub, sendInterval.timerSend);
---------------------------
上面調(diào)用的 getAllSensors 函數(shù)盡管很簡單,但是也會被刪除:其更新嵌入式系統(tǒng)保存的當(dāng)前時間,針對每次測量調(diào)用 readSensor() 函數(shù) - 距離、溫度、3 軸加速度、3 軸陀螺儀。 readSensor() 僅僅讀取文件并打印錯誤到終端。否者它和 readFile() 函數(shù)非常類似。
---------------------------
//Function that reads data from sensor
function readSensor(path, callback) {
fs.readFile(path, function (err, data) {
if(err){//if data could not be read
console.log("Error reading sensor:" + err);
callback(err, null);//pass the error to thecallback
return;
}
callback(null, data);//callback withouterror
});
}
sendToIotHub() 函數(shù)將最新的數(shù)據(jù)轉(zhuǎn)換成JSON 編碼字符串、封裝成消息、在終端輸出反饋并將其發(fā)送至 IoT Hub。這也是本文解釋最后一部分代碼,所示如下:
---------------------------
function sendToIotHub() {
// Add the data to a JSON encoded string
var data = JSON.stringify({
ObjectName: 'toradex2',
ObjectType: 'SensorTagEvent',
temp: temperature,
acceleration: Acceleration,
gyroscope: Gyroscope,
gps: gps_coordinates,
distance: Distance,
boardTime: timenow
});
var message = new Message(data);// Encapsulatethe message to be sent
message.properties.add('myproperty','myvalue');
console.log('sending message to the IoTHub: ');// Feedback message to the console
console.log(data);
client.sendEvent(message,printResultFor('send'));// Send message to the IoT Hub
}
---------------------------
5). 總結(jié)
到現(xiàn)在為止,在本系列的第一篇文章中介紹了項目目標(biāo)和 IoT 總體情況。然后配置 Azure IoT Hub,接收來自 Toradex 嵌入式系統(tǒng)的消息(并發(fā)送消息,在該項目中沒有過多說明),提出了一些關(guān)于從嵌入式系統(tǒng)發(fā)送數(shù)據(jù)的思考,最后,演示了從云端獲取數(shù)據(jù)的方法,用以驗證系統(tǒng)正常工作。
然后,本文主要關(guān)注于嵌入式系統(tǒng)的項目。從如何連接傳感器/模塊到 Colibri VF61 + Iris 載板的步驟開始到 Node 應(yīng)用的具體細(xì)節(jié)。
基于以上內(nèi)容,接下來的內(nèi)容是為了減輕挖掘有用的分析并生成 BI 工作,介紹使用 Azure Stream Analytics 和 Microsoft Power BI 過濾數(shù)據(jù)并顯示易于理解的結(jié)果。希望這是一篇有用的文章,我也想要感謝來自巴西的 Grupo Viceri 團(tuán)隊在 Azure 和 BusinessIntelligence 豐富的經(jīng)驗,促成了我們的合作,并最終實現(xiàn)了 IoT 項目。期待在第三部分文章中再見!
提交
Verdin AM62 LVGL 移植
基于 NXP iMX8MM 測試 Secure Boot 功能
隆重推出 Aquila - 新一代 Toradex 計算機模塊
Verdin iMX8MP 調(diào)試串口更改
NXP iMX8MM Cortex-M4 核心 GPT Capture 測試